#include <iostream>
#include <cassert>

template<typename T>
class UniquePtr
{
public:
    explicit UniquePtr(T* pResource = nullptr) : m_pResource(pResource) {}
    ~UniquePtr() { del(); }

    //禁用拷贝
    UniquePtr(const UniquePtr&) = delete;
    UniquePtr& operator=(const UniquePtr&) = delete;

    //支持移动
    UniquePtr(UniquePtr&& other) noexcept : m_pResource(other.m_pResource) {
        other.m_pResource = nullptr;
    }

    UniquePtr& operator=(UniquePtr&& other) noexcept {
        if (this != &other) {
            del();
            m_pResource = other.m_pResource;
            other.m_pResource = nullptr;
        }
        return *this;
    }

    void reset(T* pResource = nullptr) {
        del();
        m_pResource = pResource;
    }

    T* release() {
        T* tmp = m_pResource;
        m_pResource = nullptr;
        return tmp;
    }

    T* get() const { return m_pResource; }

    explicit operator bool() const { return m_pResource != nullptr; }

    T& operator*() const {
        assert(m_pResource != nullptr);
        return *m_pResource;
    }

    T* operator->() const {
        assert(m_pResource != nullptr);
        return m_pResource;
    }

private:
    void del() {
        if(m_pResource) {
            delete m_pResource;
            m_pResource = nullptr;
        }
    }

    T* m_pResource;
};

void testUniquePtr() {
    UniquePtr<int> up1(new int(10));
    std::cout << "*up1 = " << *up1 << std::endl; // 输出 10

    if (up1) {
        std::cout << "up1 is not null" << std::endl;
    }

    // 转移所有权给 up2
    UniquePtr<int> up2 = std::move(up1);
    std::cout << "*up2 = " << *up2 << std::endl;

    if (!up1) {
        std::cout << "up1 is now null after move" << std::endl;
    }

    // reset 测试
    up2.reset(new int(20));
    std::cout << "*up2 after reset = " << *up2 << std::endl;

    // release 测试
    int* raw = up2.release();
    std::cout << "Released raw pointer value = " << *raw << std::endl;
    delete raw; // 手动释放，因为 ownership 被释放了

    if (!up2) {
        std::cout << "up2 is null after release" << std::endl;
    }

    // reset 空指针
    up2.reset();
    std::cout << "reset to nullptr successful" << std::endl;
}

int main() {
    testUniquePtr();
    return 0;
}